using System;
using System.Collections;
using System.Collections.Generic;

using PluginInstanceAlias = EpisodeWizard.Core.PluginManager<EpisodeWizard.Core.QueryPlugin>.PluginInstance;



namespace EpisodeWizard.Core
{
	//
	// File: Videos/Will and grace/503. In the park.avi
	//
	// Identification:	Videos, Will and grace, In the park
	//
	// EpGuides
	// Videos: nothing
	// Will and grace: Wilma (wilma 2), Will and grace (willandgrace 4)
	// In the park: South park (southpark 2)
	//
	// TVRage
	// Videos: nothing
	// Will & grace: Will and grace (willngrace 4)
	// In the park: nothing
	//
	// EpisodeFile.PossibleShows
	// Will and grace, 8, Epguides=Willandgrace, TVRage=willngrace
	// Wilma, 2, 
	// South park, 2, 
	//



	/// <summary>
	/// Info about a TV show episode
	/// </summary>
	public class EpisodeInfo
	{
		public string Title;
		public DateTime AirDate;
	}


	/// <summary>
	/// Identifies a show for a particular plugin
	/// </summary>
	public class TVShowPluginId
	{
		public QueryPlugin PluginInstance;
		public string ShowId;
		public int Weight;
	}


	/// <summary>
	/// Identifies a TV show, with links to the plugin instances
	/// </summary>
	public class TVShow
	{
		public string ShowName;
		public List<TVShowPluginId> PluginIds = new List<TVShowPluginId>();
		
		public override string ToString()
		{
			return ShowName;
		}
	}


	/// <summary>
	/// Represents the possible guesses for a given file
	/// The series name and episode numbers are guessed using the parent folder and filename
	/// </summary>
	public class EpisodeFile
	{

        public EpisodeFile(string _Filepath, string _RootFolder)
		{
			Filepath = _Filepath;
			RootFolder = _RootFolder;
		}

		/// <summary>
		/// The path and name of the file
		/// </summary>
		public string Filepath;

		/// <summary>
		/// The folder it was added from, for a user-friendly display
		/// </summary>
		public string RootFolder;

		/// <summary>
		/// The new filename given by the application (without path)
		/// </summary>
		public string NewFilename;

		/// <summary>
		/// The list of series this file is likely to belong to
		/// </summary>
		public Guess<TVShow> PossibleShows = new Guess<TVShow>();

		/// <summary>
		/// The list of episodes this file is likely to be (season number and episode number)
		/// </summary>
		public Guess<EpisodeNumber> PossibleEpisodes = new Guess<EpisodeNumber>();

		/// <summary>
		/// The list of episodes this file is likely to be (season number and episode number)
		/// </summary>
		public Guess<string> PossibleTitles = new Guess<string>();

		/// <summary>
		/// Returns true if there is a selected value for all the possible guesses
		/// </summary>
		public bool HasAllInformation()
		{
			return (PossibleShows.SelectedValue != null
					&& PossibleEpisodes.SelectedValue != null
					&& PossibleTitles.SelectedValue != null);
		}

		/// <summary>
		/// Try to identify this episode file
		/// </summary>
		public void Identify()
		{
			IdentifyShow();
			PossibleShows.AutoSelect();

			IdentifyEpisode();
			PossibleEpisodes.AutoSelect();
		}


		/// <summary>
		/// Identify the tv show that this can be
		/// </summary>
		private void IdentifyShow()
		{
			PossibleShows.Choices.Clear();

			List<FileIdentification.WeightedGuess<FuzzyString>> ShowGuesses = FileIdentification.IdentifyShow(this);
			foreach (FileIdentification.WeightedGuess<FuzzyString> Guess in ShowGuesses)
			{
				// See if plugins have some shows that sound like this
				List<TVShowPluginId> PluginShows = new List<TVShowPluginId>();
				foreach (PluginInstanceAlias Plugin in Core.Program.GetInstance().Plugins)
				{
					if (Plugin.Active)
					{
						PluginShows.AddRange(Plugin.Instance.GetSimilarShows(Guess.Value));
					}
				}

				// Add them	
				if (PluginShows.Count > 0)
				{
					foreach (TVShowPluginId PId in PluginShows)
					{
						// TODO check if the show is not already added
						TVShow Show = new TVShow();
						Show.ShowName = PId.ShowId;
						Show.PluginIds.Add(PId);

						// Identical matches are much better than approximate ones
						int TotalWeight = PId.Weight * Guess.Weight;
						if (PId.Weight == (int) FuzzyString.Resemblance.Identical)
						{
							TotalWeight *= 2;
						}

						PossibleShows.Choices.Add(Show, PId.Weight * Guess.Weight);						
					}
				}
			}
		}


		/// <summary>
		/// Identify the possible episodes that this can be
		/// </summary>
		private void IdentifyEpisode()
		{
			PossibleEpisodes.Choices.Clear();
			List<EpisodeNumber> EpisodeGuesses = FileIdentification.IdentifyEpisode(this);
			foreach (EpisodeNumber Guess in EpisodeGuesses)
			{
				PossibleEpisodes.Choices.Add(Guess, 1);		// All equi-probable
			}
		}


		/// <summary>
		/// Queries the plugins to find the episode title
		/// </summary>
		public void QueryTitle()
		{
			foreach (TVShowPluginId Plugin in PossibleShows.SelectedValue.PluginIds)
			{
				EpisodeInfo Info = Plugin.PluginInstance.GetEpisodeInfo(Plugin.ShowId, PossibleEpisodes.SelectedValue.Season, PossibleEpisodes.SelectedValue.Episode);
				if (Info != null)
				{
					PossibleTitles.AddChoice(Info.Title, 1);
				}
			}
		}
	}



	/// <summary>
	/// Season and episode number
	/// </summary>
	public class EpisodeNumber
	{
		public EpisodeNumber(int _Season, int _Episode)
		{
			Season  = _Season;
			Episode = _Episode;
		}

		public int Season;
		public int Episode;

		public override string ToString()
		{
			return "s" + Season.ToString("00") + " e" + Episode.ToString("00");
		}
	}


}

